#ifndef NODE_H
#define NODE_H

#include "Segment.h"
#include "SPSegment.h"
#include "Comparator.h"
#include "Index_Iterator.h"
#include "IndexVisualizer.h"
#include <vector>


struct SplitOp {
    bool splitPerformed;
    unsigned newPageId;
    char* key;
};

struct NodeHeader
{
    bool isLeaf;
    bool hasNext;
    unsigned nextPageId;
    unsigned entryCount;
};

struct RemovalResult
{
    bool removed;
    bool nowEmpty;
    bool redirectNext;
    bool wasNode;
    unsigned newNext;
    unsigned keepChildId;
    bool lastOneDeleted;
    char* newKey;

    RemovalResult() : removed(false), nowEmpty(false), redirectNext(false), wasNode(false), lastOneDeleted(false), newKey(NULL) {}
};

struct NodeContext
{
    unsigned keyLen;
    Comparator compare;
    Segment& segment;

    NodeContext(unsigned keyLength, Comparator comparator, Segment& segment) : keyLen(keyLength), compare(comparator), segment(segment) {}
    NodeContext(const NodeContext& other) : keyLen(other.keyLen), compare(other.compare), segment(other.segment) {}

    ~NodeContext() {}
    NodeContext operator=(const NodeContext& other) = delete;
};

class Node
{

private:
    unsigned segmentPageId; // Aus Sicht des Segments!
    BufferFrame* tmpPage;
    Node* parent;
    NodeContext& context;

    void releaseWriteLock();
    void releaseParentsWriteLock();

public:
    Node(unsigned segmentPageId, NodeContext& nodeContext) : segmentPageId(segmentPageId), tmpPage(NULL), parent(NULL), context(nodeContext) {}

    bool insert(char* key, TID tid);
    SplitOp insertExt(char* key, TID tid);
    RemovalResult* remove(char* key, bool isRoot);
    TID lookup(char* key);
    index_iterator lookupRange(char* key1, char* key2);
    void visualize(IndexVisualizer& vis);
    void redirectNext(unsigned newNeighbour, bool lastOneDeleted);
    char* getLeftKey();
};

#endif // NODE_H_INCLUDED
